/*
 * Copyright (C) 2016 Jared Rummler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.jaredrummler.materialspinner;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.VectorElement;
import ohos.agp.render.ColorMatrix;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;

/**
 * A spinner that shows a under the view when clicked.
 */
public class MaterialSpinner extends Text implements Component.TouchEventListener {

    private MaterialSpinnerBaseAdapter adapter;
    private ListContainer listView;
    int paddingLeft, paddingTop, paddingRight, paddingBottom = 12;
    private ToastDialog toastDialog;
    private String[] items;
    private boolean hideArrow;
    private boolean nothingSelected;
    private int popupWindowMaxHeight;
    private int popupWindowHeight;
    private int selectedIndex;
    private int backgroundColor;
    private int backgroundSelector;
    private int arrowColor;
    private Color arrowColorDisabled;
    private Color textColor;
    private Color hintColor;
    private int padding_top = 12;
    private int padding_left = 12;
    private int padding_bottom = 12;
    private int padding_right = 12;
    private int popupPaddingTop;
    private int popupPaddingLeft;
    private int popupPaddingBottom;
    private int popupPaddingRight;
    private String hintText;
    private OnNothingSelectedListener onNothingSelectedListener;
    private OnItemSelectedListener onItemSelectedListener;


    public MaterialSpinner(Context context) {
        super(context);
        this.mContext = context;
        init(context, null);
    }

    public MaterialSpinner(Context context, AttrSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init(context, attrs);
    }

    public MaterialSpinner(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, "");
        init(context, attrs);
    }

    private void init(Context context, AttrSet attrs) {
        int paddingLeft = 12, paddingTop = 12, paddingRight = 12, paddingBottom = 12;
        int defaultPaddingLeft, defaultPaddingTop, defaultPaddingRight, defaultPaddingBottom;
        int defaultPopupPaddingLeft, defaultPopupPaddingTop, defaultPopupPaddingRight, defaultPopupPaddingBottom;

        defaultPaddingLeft = defaultPaddingRight =
                defaultPaddingBottom = defaultPaddingTop = 12;

        defaultPaddingRight = 24;

        defaultPopupPaddingLeft =
                defaultPopupPaddingRight = 24;
        defaultPopupPaddingTop = defaultPopupPaddingBottom = 12;

        backgroundSelector = ResourceTable.Graphic_selectdialog;

        if (attrs != null) {
            backgroundColor = attrs.getAttr("ms_background_color").isPresent() ?
                    attrs.getAttr("ms_background_color").get().getColorValue().getValue() : 0xf5f5f5;
            textColor = attrs.getAttr("ms_text_color").isPresent() ?
                    attrs.getAttr("ms_text_color").get().getColorValue() : Color.BLACK;
            arrowColor = attrs.getAttr("ms_arrow_tint").isPresent() ?
                    attrs.getAttr("ms_arrow_tint").get().getColorValue().getValue() : 0x000000;
            hideArrow = attrs.getAttr("ms_hide_arrow").isPresent() ?
                    attrs.getAttr("ms_hide_arrow").get().getBoolValue() : false;
            popupWindowMaxHeight = attrs.getAttr("ms_dropdown_max_height").isPresent() ?
                    attrs.getAttr("ms_dropdown_max_height").get().getDimensionValue() : 900;

            padding_top = attrs.getAttr("ms_padding_top").isPresent() ?
                    attrs.getAttr("ms_padding_top").get().getDimensionValue() : defaultPaddingTop;
            padding_left = attrs.getAttr("ms_padding_left").isPresent() ?
                    attrs.getAttr("ms_padding_left").get().getDimensionValue() : defaultPaddingLeft;
            padding_bottom = attrs.getAttr("ms_padding_bottom").isPresent() ?
                    attrs.getAttr("ms_padding_bottom").get().getDimensionValue() : defaultPaddingBottom;
            padding_right = attrs.getAttr("ms_padding_right").isPresent() ?
                    attrs.getAttr("ms_padding_right").get().getDimensionValue() : defaultPaddingRight;

            popupPaddingTop = attrs.getAttr("ms_popup_padding_top").isPresent() ?
                    attrs.getAttr("ms_popup_padding_top").get().getDimensionValue() : defaultPopupPaddingTop;
            popupPaddingLeft = attrs.getAttr("ms_popup_padding_left").isPresent() ?
                    attrs.getAttr("ms_popup_padding_left").get().getDimensionValue() : defaultPopupPaddingLeft;
            popupPaddingBottom = attrs.getAttr("ms_popup_padding_bottom").isPresent() ?
                    attrs.getAttr("ms_popup_padding_bottom").get().getDimensionValue() : defaultPopupPaddingBottom;
            popupPaddingRight = attrs.getAttr("ms_popup_padding_right").isPresent() ?
                    attrs.getAttr("ms_popup_padding_right").get().getDimensionValue() : defaultPopupPaddingRight;

        } else {
            arrowColor = 0x00ff00;
        }

        setTouchEventListener(this);
        initComponent();
    }


    private void initComponent() {
        setTextAlignment(TextAlignment.VERTICAL_CENTER);
        this.setClickable(true);
        this.setTextColor(textColor);

        setPadding(padding_left, padding_top, padding_right, padding_bottom);
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setShape(ShapeElement.RECTANGLE);
        try {
            shapeElement.setRgbColor(new RgbColor(((backgroundColor >> 16) & 0xFF), ((backgroundColor >> 8) & 0xFF), ((backgroundColor) & 0xFF)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.setBackground(shapeElement);

        this.setTextSize(50);

        try {
            VectorElement vectorElement = new VectorElement(mContext, ResourceTable.Media_ms__menu_down);
            ColorMatrix colorMatrix = new ColorMatrix();
            int color = Color.getIntColor(String.format("#%06X", (0xFFFFFF & arrowColor)));
            colorMatrix.setScale(((color >> 16) & 0xFF),
                    ((color >> 8) & 0xFF),
                    ((color) & 0xFF),
                    ((color >> 24) & 0xFF));
            vectorElement.setColorMatrix(colorMatrix);

            if (hideArrow) {
                setAroundElements(null, null, null, null);
            } else {
                setAroundElements(null, null, vectorElement, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private float getRgbaColor(int color, String colstr) {
        float red = (color >> 16) & 0xFF;
        float green = (color >> 8) & 0xFF;
        float blue = (color) & 0xFF;
        float alpha = (color >> 24) & 0xFF;
        if (colstr.equals(red))
            return red;
        if (colstr.equals(green))
            return green;
        if (colstr.equals(blue))
            return blue;
        if (colstr.equals(alpha))
            return alpha;
        return red;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        if (event.getAction() == TouchEvent.PRIMARY_POINT_UP) {
            if (isEnabled() && isClickable()) {
                expand();
            }
        }
        return true;
    }

    /**
     * Set the dropdown items
     *
     * @param items A list of items
     * @param <T>   The item type
     */
    public <T> void setItems(String[] items) {
        this.setText(items[0]);
        this.items = items;
    }

    public void setTextCustomColor(Color textColor) {
        this.textColor = textColor;
        initComponent();
    }

    public void setHideArrow(boolean hideArrow) {
        this.hideArrow = hideArrow;
        initComponent();
    }

    public boolean getHideArrow() {
        return hideArrow;
    }

    public void setBackgroundColor(int backgroundColor) {
        this.backgroundColor = backgroundColor;
        initComponent();
    }

    public int getBackgroundColor() {
        return backgroundColor;
    }

    public void setBackgroundSelector(int backgroundSelector) {
        this.backgroundSelector = backgroundSelector;
        initComponent();
    }

    /**
     * Show the dropdown menu
     */
    public void expand() {
        VectorElement vectorElement = null;
        try {
            vectorElement = new VectorElement(mContext, ResourceTable.Media_ms__menu_up);
            ColorMatrix colorMatrix = new ColorMatrix();
            int color = Color.getIntColor(String.format("#%06X", (0xFFFFFF & arrowColor)));
            colorMatrix.setScale(((color >> 16) & 0xFF),
                    ((color >> 8) & 0xFF),
                    ((color) & 0xFF),
                    ((color >> 24) & 0xFF));
            vectorElement.setColorMatrix(colorMatrix);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (hideArrow) {
            setAroundElements(null, null, null, null);
        } else {
            setAroundElements(null, null, vectorElement, null);
        }

        String[] finalItems = items;
        List<String> list = new ArrayList<String>(Arrays.asList(finalItems));
        list.remove(getText());
        String[] str_array = list.toArray(new String[0]);
        new PopupCustomDialog.Builder(mContext)
                .items(str_array)
                .setMaxPopupHeight(popupWindowMaxHeight)
                .setPopupPadding(popupPaddingLeft, popupPaddingTop, popupPaddingRight, popupPaddingBottom)
                .setCustomTextColor(textColor)
                .setBackgroundColor(backgroundColor)
                .setBackgroundSelecorColor(backgroundSelector)
                .nothingItemsCallback(new PopupCustomDialog.NothingListCallback() {
                    @Override
                    public void onSelection(PopupCustomDialog dialog, Component itemView, int position, CharSequence text) {
                        if (onNothingSelectedListener != null) {
                            onNothingSelectedListener.onNothingSelected();
                        }
                        collapse();
                    }
                })
                .itemsCallback(new PopupCustomDialog.ListCallback() {
                    @Override
                    public void onSelection(PopupCustomDialog dialog, Component view, int which, CharSequence text) {
                        setTextToSpinner(text.toString());
                        if (onItemSelectedListener != null) {
                            onItemSelectedListener.onItemSelected(MaterialSpinner.this, which, text.toString());
                        }
                        collapse();
                    }
                })
                .show();
    }


    /**
     * Register a callback to be invoked when the  is shown but the user didn't select an item.
     *
     * @param onNothingSelectedListener the callback that will run
     */
    public void setOnNothingSelectedListener(OnNothingSelectedListener onNothingSelectedListener) {
        this.onNothingSelectedListener = onNothingSelectedListener;
    }

    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        this.onItemSelectedListener = onItemSelectedListener;
    }

    public interface OnItemSelectedListener<T> {

        /**
         * <p>Callback method to be invoked when an item in this view has been selected. This callback is invoked only when
         * the newly selected position is different from the previously selected position or if there was no selected
         * item.</p>
         *
         * @param view     The {@link MaterialSpinner} view
         * @param position The position of the view in the adapter
         * @param text     The row text of the item that is selected
         */
        void onItemSelected(MaterialSpinner view, int position, String text);
    }

    /**
     * Interface definition for a callback to be invoked when the dropdown is dismissed and no item was selected.
     */
    public interface OnNothingSelectedListener {

        /**
         * Callback method to be invoked when the is dismissed and no item was selected.
         */
        void onNothingSelected();
    }

    /**
     * Closes the dropdown menu
     */
    public void collapse() {
        VectorElement vectorElement = null;
        try {
            vectorElement = new VectorElement(mContext, ResourceTable.Media_ms__menu_down);
            ColorMatrix colorMatrix = new ColorMatrix();
            int color = Color.getIntColor(String.format("#%06X", (0xFFFFFF & arrowColor)));
            colorMatrix.setScale(((color >> 16) & 0xFF),
                    ((color >> 8) & 0xFF),
                    ((color) & 0xFF),
                    ((color >> 24) & 0xFF));
            vectorElement.setColorMatrix(colorMatrix);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (hideArrow) {
            setAroundElements(null, null, null, null);
        } else {
            setAroundElements(null, null, vectorElement, null);
        }
    }

    private void setTextToSpinner(String message) {
        this.setText(message);
    }

    private void showToast(String message) {
        this.setText(message);
        if (toastDialog != null) {
            toastDialog.cancel();
            toastDialog = null;
        }
        toastDialog = new ToastDialog(mContext);
        ComponentContainer componentContainer = (ComponentContainer) LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_item_toast, null, false);
        Text messageTV = (Text) componentContainer.findComponentById(ResourceTable.Id_toast_text);
        DependentLayout background = (DependentLayout) componentContainer.findComponentById(ResourceTable.Id_background);
        messageTV.setText(message);
        ShapeElement infoShapeElement = new ShapeElement();
        infoShapeElement.setRgbColor(new RgbColor(0, 0, 0));
        background.setBackground(infoShapeElement);

        toastDialog.setContentCustomComponent(componentContainer);
        toastDialog.setAlignment(TextAlignment.BOTTOM);
        toastDialog.setSize(1000, MATCH_CONTENT).show();
    }
}